package com.zeng.sboot.redis.demo.controller;

import com.zeng.sboot.redis.demo.config.RedisInitialize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@RequestMapping("/jedis")
public class JedisController {

    /**
     * 直接注入使用 RedisConnectionFactory 操作
     */
    @Resource
    protected RedisConnectionFactory redisConnectionFactory;

    /**
     * spring 提供的两个模板 RedisTemplate<String, Object> 和 StringRedisTemplate<String, String> 直接注入使用
     * RedisTemplate 是 key 为 String value 为 Object 的 RedisTemplate<String, Object> 类型
     * StringRedisTemplate 是 key 和 value 都为 String 的 StringRedisTemplate<String, String> 类型
     */
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @RequestMapping("/hash")
    public String hash(){

        ValueOperations<String, String> forValue = stringRedisTemplate.opsForValue();//字符操作对象
        HashOperations<String, Object, Object> forHash = stringRedisTemplate.opsForHash();//hash散列表操作对象
        ListOperations<String, String> forList = stringRedisTemplate.opsForList();//双向链表操作对象
        SetOperations<String, String> forSet = stringRedisTemplate.opsForSet();//无序散列表操作对象
        ZSetOperations<String, String> forZSet = stringRedisTemplate.opsForZSet();//排序散列表操作对象

        /**
         * 1. 使用 RedisConnection 方式操作, 但是每次添加的 key 和 value 都是 byte 类型
         *      redis 库中存的 byte 类型, 无法一目了然
         */
        RedisConnection connection = redisConnectionFactory.getConnection();
        connection.set("classno".getBytes(), "yuwen".getBytes());
        byte[] classnobyte = connection.get("classno".getBytes());
        String classno = new String(classnobyte);
        System.out.println(classno);
        /**
         * 2. 直接使用 spring 提供的两个模板 RedisTemplate<String, Object>
         *     和 StringRedisTemplate 直接注入使用
         */
        forValue.set("sex", "boy");
        String sex = forValue.get("sex");
        System.out.println(sex);

        redisTemplate.opsForValue().set("age", 18);
        Integer age = (Integer) redisTemplate.opsForValue().get("age");
        System.out.println(age);

        forValue.set("username", "zhangsan");
        String username = forValue.get("username");

        System.out.println(username);
        return username;
    }

    @RequestMapping(value = "/auto")
    @Cacheable(cacheNames = "user.service.all")
    public String getAll(){
        return "all";
    }

    /**
     * 在 Redis 中创建了一个key为 redis.string.username~keys 的键
     *
     * 使用 @Cacheable , 因为 RedisInitialize 中 extends CachingConfigurerSupport 重写了方法 keyGenerator，调用方法时会自动在Redis中自动创建 类.方法名 的键
     *
     *
     * @return
     */
    @RequestMapping(value = "/str")
    @Cacheable(value = "redis.string.username") // 在 Redis 中创建了一个key为 redis.string.username~keys 的键
    public String string() {
        ValueOperations<String, String> forValue = stringRedisTemplate.opsForValue();//字符操作对象
        forValue.set("username","username ' Name");
        return forValue.get("username");
    }

    @RequestMapping(value = "/toAll")
    public String toAll() {
        return "toAll";
    }

    /**
     * 使用 @Cacheable 时务必要指定一个value或cacheNames，会创建value指定名称的key，然后
     * 如果重写了 extends CachingConfigurerSupport 的方法 keyGenerator ，还会再创建一个keyGenerator指定的key的生成方式 ，如果 类.方法名
     *
     * 如下是指定另外的 keyGenerator 生成方式
     *
     * @return
     */
    @Cacheable(keyGenerator = "redisKeyGenerator", value = "toall3")
    @RequestMapping(value = "/toAll3")
    public String toAll2() {
        ValueOperations<String, String> forValue = stringRedisTemplate.opsForValue();//字符操作对象
        forValue.set("username3","username ' Name3");
        return forValue.get("username3");
    }
}
